home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 151-175 / disk_152 / blk / blk.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  26KB  |  1,086 lines

  1. /*
  2.  * Automatic Requester formatter and generator
  3.  * Reads a requester description and formats graphically
  4.  * then generates the appropriate C-code to specify the requester.
  5.  * See the examples and the documentaion for using the program.
  6.  **
  7.  *  Process flow:
  8.  * Box structure read by recursive-descent
  9.  * Boxes formatted, also recursively
  10.  * Borders generated and resolved into a minimum set of Border structs
  11.  * File written, sometimes linearly, sometimes recursively
  12.  **
  13.  *  Problems:
  14.  * The file reading isn't the most elegant in the world, relying on global
  15.  * variables and backspacing to look ahead.  A more general lexical approach
  16.  * would be nice so that macros could be included (macros are sorely
  17.  * needed).  Also, the file formatted front-end is not the most
  18.  * user-friendly in the world and something more mouse-driven would be
  19.  * neat.  The source-code generation is not terribily elegant either.  A
  20.  * better approach would be to build the actual structures used in the
  21.  * requester dynamically so the requester in the preview window could
  22.  * actually be played with, and generating source-code would be just a
  23.  * matter of dumping the structures to a file.  Borders do this already, and
  24.  * it's somewhat more understandable than the other structures.
  25.  **
  26.  *  Disclaimer:
  27.  * This is a tool I hacked up for my own use in creating requesters for
  28.  * Modeler 3D.  It works for me, but I make no claim as to the robustness or
  29.  * other quality of the code.  Personally I shudder at the thought of
  30.  * re-writing this into a real general-purpose tool just because bulk of
  31.  * the code is so poorly written.  It does give a nice example of
  32.  * recursive-decent parsing, and the box layout stuff is kind of neat and
  33.  * can be put to good use in other places.
  34.  **
  35.  * Please inform my of any changes or improvements.  Enjoy.
  36.  */
  37.  
  38. #include <stdio.h>
  39. #include <functions.h>
  40. #include <exec/types.h>
  41. #include <intuition/intuition.h>
  42.  
  43.  
  44. /* Useful defines */
  45.  
  46. #define NEW(typ)        (typ*)AllocMem((LONG)sizeof(typ),0L)
  47. #define FREE(p,typ)     FreeMem(p,(LONG)sizeof(typ))
  48. #define NEW_N(typ,n)    (typ*)AllocMem((LONG)((n)*sizeof(typ)),0L)
  49. #define FREE_N(p,typ,n) FreeMem(p,(LONG)((n)*sizeof(typ)))
  50. #define BACKSPACE       if (gc != -1) ungetc(gc,file)
  51. #define abs(x)          ((x)<0 ? -(x) : (x))
  52.  
  53. /* Box types */
  54.  
  55. #define HBOX 1
  56. #define VBOX 2
  57. #define FILL 3
  58. #define BLOK 4
  59. #define TEXT 5
  60. #define HRULE 6
  61. #define VRULE 7
  62.  
  63. /* Dimension limits */
  64.  
  65. #define MAX_GAD 50
  66. #define BUF_SIZ 500
  67.  
  68. /* A requester is constructed from a tree of Boxes
  69.  * Boxes are arranged in a binary tree, one subtree is what is inside the
  70.  * Box (sub), the other is the remaining Boxes at the same level (next).
  71.  */
  72. typedef struct Box {
  73.    short type,    /* box type - possibilities defined above */
  74.      gid,         /* Gadget id code (0 if none) */
  75.      col;         /* color - for borders and text */
  76.    short xs,ys,   /* box size (x,y) */
  77.      x,y,         /* box position (x,y) */
  78.      nfil;        /* number of filers inside this box */
  79.    char *val;     /* string for text boxes */
  80.    struct Box *next,*sub;  /* binary tree links */
  81. } BOX;
  82.  
  83. /* Information on each gadget, zero-th is default
  84.  */
  85. struct GadInfo {
  86.    short gid,  /* gadget id code */
  87.      str,      /* string gadget */
  88.      prp;      /* prop gadget */
  89.    char *actf, /* flag string */
  90.      *gnam;    /* gadget name (GadgetID field) */
  91. }
  92.   ginfo[MAX_GAD] = { -1,-1,-1,"v",NULL };
  93.  
  94. /* GLOBAL */
  95.  
  96. FILE *file;          /* input and output files */
  97. int gc;              /* last character read */
  98. char buf[BUF_SIZ];   /* big buffer for holding strings */
  99. short bufpos=0;      /* position of free space in buf */
  100. char base[10];       /* base name */
  101. short ngad=0,igad=0,ntxt=0,itxt=0,  /* counters for gadgets, ituitexts, */
  102.  nstr=0,istr=0,nprp=0,iprp=0;       /* string and prop gadgets */
  103. short lgad=1;        /* counter for gadinfo array (0 already defined) */
  104. short def_bcol=1,def_tcol=1;     /* default border and text colors */
  105. struct Border *blst = NULL;      /* list header for border structs */
  106.  
  107. /* generic border and intuitext structs
  108.  */
  109. struct Border brd = {0,0,1,0,JAM1,2,NULL,NULL};
  110. struct IntuiText it = {1,0,JAM2,0,0,NULL,NULL,NULL};
  111.  
  112. /* the preview window
  113.  */
  114. struct NewWindow nwin = {
  115.    0,0,300,150,
  116.    -1,-1,0,WINDOWDEPTH|WINDOWDRAG|SMART_REFRESH,
  117.    NULL,NULL,(UBYTE*)"Blocks",NULL,
  118.    NULL,0,0,0,0,WBENCHSCREEN
  119. };
  120.  
  121. struct IntuitionBase *IntuitionBase;
  122.  
  123.  
  124. /* Returns pointer to string containing box type name
  125.  */
  126. char *BoxType (typ)
  127.    short typ;
  128. {
  129.    switch (typ) {
  130.       case HBOX: return ("HBOX");
  131.       case VBOX: return ("VBOX");
  132.       case BLOK: return ("BLOK");
  133.       case TEXT: return ("TEXT");
  134.       case FILL: return ("FILL");
  135.       case HRULE: return ("HRULE");
  136.       case VRULE: return ("VRULE");
  137.    }
  138. }
  139.  
  140.  
  141. /* Returns a new, initialized Box struct
  142.  */
  143. BOX *NewBox (type)
  144.    short type;
  145. {
  146.    BOX *b;
  147.  
  148.    b = NEW(BOX);
  149.    b->type = type;
  150.    b->nfil = b->gid = 0;
  151.    b->val = NULL;
  152.    b->next = b->sub = NULL;
  153. }
  154.  
  155.  
  156. /* Recursively frees Box tree
  157.  */
  158. FreeBox (box)
  159.    BOX *box;
  160. {
  161.    if (!box) return;
  162.    FreeBox (box->sub);
  163.    FreeBox (box->next);
  164.    FREE(box,BOX);
  165. }
  166.  
  167.  
  168. /* Recursively examine all nodes of Box tree and allocate Border structs
  169.  * for all the HRULE and VRULE boxes.  Adds new Borders to the main list.
  170.  */
  171. CreateBorder (box)
  172.    register BOX *box;
  173. {
  174.    register struct Border *bd;
  175.  
  176.    if (!box) return;
  177.  
  178.    if (box->type == HRULE || box->type == VRULE) {
  179.       bd = NEW(struct Border);
  180.       *bd = brd;
  181.       bd->FrontPen = box->col;
  182.       bd->XY = NEW_N(SHORT,4);
  183.       bd->XY[0] = bd->XY[2] = box->x;
  184.       bd->XY[1] = bd->XY[3] = box->y;
  185.       if (box->type == HRULE) {
  186.          bd->XY[2] += box->xs-1;
  187.       } else {
  188.          bd->XY[3] += box->ys-1;
  189.       }
  190.       bd->NextBorder = blst;
  191.       blst = bd;
  192.    }
  193.    CreateBorder (box->sub);
  194.    CreateBorder (box->next);
  195. }
  196.  
  197.  
  198. /* debug routine
  199. PrintBorder ()
  200. {
  201.    struct Border *b;
  202.    short i;
  203.  
  204.    for (b=blst; b; b=b->NextBorder) {
  205.       printf ("%d %d %d %d\n:: ", b->LeftEdge, b->TopEdge, b->FrontPen, b->Count);
  206.       for (i=0; i<b->Count; i++) printf ("%d,%d ", b->XY[i*2],b->XY[i*2+1]);
  207.       printf ("\n");
  208.    }
  209. }
  210. */
  211.  
  212.  
  213. /* Frees all Border structs in main Border list
  214.  */
  215. FreeBorder ()
  216. {
  217.    register struct Border *b,*nxt;
  218.  
  219.    for (b=blst; b; b=nxt) {
  220.       nxt = b->NextBorder;
  221.       FREE_N(b->XY,SHORT,b->Count*2);
  222.       FREE(b,struct Border);
  223.    }
  224. }
  225.  
  226.  
  227. /* Examines all the Borders in the list for adjacency.  Any borders that
  228.  * could use the same set of polyline commands are merged into a single
  229.  * struct.
  230.  */
  231. MergeBorders ()
  232. {
  233.    register struct Border *a,*b;
  234.    short i0,i1,x,y,*xy,j;
  235.    register short i,ac,bc,merge;
  236.  
  237.    do {
  238.       merge = -1;
  239.       for (a=blst; a; a=a->NextBorder) {
  240.          for (b=a->NextBorder; b; b=b->NextBorder) {
  241.             if (a->FrontPen != b->FrontPen) continue;
  242.             ac = a->Count;
  243.             bc = b->Count;
  244.             for (i0=0; i0<2; i0++) for (i1=0; i1<2; i1++) {
  245.                x = a->XY[i0*2*(ac-1)] - b->XY[i1*2*(bc-1)];
  246.                y = a->XY[i0*2*(ac-1)+1] - b->XY[i1*2*(bc-1)+1];
  247.                if (abs(x) + abs(y) == 1) merge = (i0<<1) + i1;
  248.             }
  249.             if (merge!=-1) break;
  250.          }
  251.          if (merge!=-1) break;
  252.       }
  253.       if (merge!=-1) {
  254.          xy = NEW_N(SHORT,(bc+ac)*2);
  255.          x = (merge&2) == 0;  /* reverse a */
  256.          y = (merge&1) == 1;  /* reverse b */
  257.          j = 0;
  258.          for (i=0; i<ac; i++) {
  259.             i0 = (x ? ac-1-i : i) * 2;
  260.             xy[j++] = a->XY[i0];
  261.             xy[j++] = a->XY[i0+1];
  262.          }
  263.          for (i=0; i<bc; i++) {
  264.             i0 = (y ? bc-1-i : i) * 2;
  265.             xy[j++] = b->XY[i0];
  266.             xy[j++] = b->XY[i0+1];
  267.          }
  268.          a->Count = j/2;
  269.          FREE_N(a->XY,SHORT,ac*2);
  270.          a->XY = xy;
  271. /* free b and remove from list */
  272.          for (a=blst; a && a->NextBorder!=b; a=a->NextBorder);
  273.          a->NextBorder = b->NextBorder;
  274.          FREE_N(b->XY,SHORT,bc*2);
  275.          FREE(b,struct Border);
  276.       }
  277.    } while (merge!=-1);
  278. }
  279.  
  280.  
  281. /* Second part of Border merging: Eliminates linear segments from all
  282.  * Borders XY lists.
  283.  */
  284. MergeLinear ()
  285. {
  286.    register struct Border *b;
  287.    register short i0,i1,i2,k,*xy;
  288.  
  289.    for (b=blst; b; b=b->NextBorder) {
  290.       if (b->Count < 3) continue;
  291.       xy = b->XY;
  292.       i0 = 0;
  293.       i1 = 1;
  294.       i2 = 2;
  295.       k = 2;
  296.       while (i2 < b->Count) {
  297.          while (i2<b->Count &&
  298.           (xy[i0*2]==xy[i1*2] && xy[i1*2]==xy[i2*2] ||
  299.            xy[i0*2+1]==xy[i1*2+1] && xy[i1*2+1]==xy[i2*2+1])) {
  300.             i1++;
  301.             i2++;
  302.          }
  303.          if (i2<b->Count) {
  304.             xy[k++] = xy[i1*2];
  305.             xy[k++] = xy[i1*2+1];
  306.             i0 = i1;
  307.             i1 = i2;
  308.             i2 = i1+1;
  309.          }
  310.       }
  311.       xy[k++] = xy[i1*2];
  312.       xy[k++] = xy[i1*2+1];
  313.  
  314.       k /= 2;
  315.       if (k == b->Count) continue;
  316.       xy = NEW_N(SHORT,k*2);
  317.       for (i0=0; i0<k*2; i0++) xy[i0] = b->XY[i0];
  318.       FREE_N(b->XY,SHORT,b->Count*2);
  319.       b->XY = xy;
  320.       b->Count = k;
  321.    }
  322. }
  323.  
  324.  
  325. /* Set the XSize and YSize fields for this box and all below
  326.  */
  327. Format (box)
  328.    BOX *box;
  329. {
  330.    BOX *b;
  331.    short mx,my,sx,sy,nf;
  332.  
  333.    if (!box) {
  334.       printf ("Probably an error\nImproper leaf types\n");
  335.       return;
  336.    }
  337.  
  338. /* deal with the basis (leaf) cases */
  339.    switch (box->type) {
  340.     case BLOK:
  341.     case TEXT:
  342.       return;  /* size already set */
  343.     case FILL:
  344. /* fill node has no size */
  345.       box->xs = box->ys = 0;
  346.       box->nfil = 1;
  347.       return;
  348. /* H and VRULES have their Y and X sizes already set */
  349.     case HRULE:
  350.       box->xs = 0;
  351.       return;
  352.     case VRULE:
  353.       box->ys = 0;
  354.       return;
  355.    }
  356.  
  357. /* only H and VBOXes left
  358.  * Format each internal box
  359.  */
  360.    for (b=box->sub; b; b=b->next) Format (b);
  361.  
  362. /* compute total and max sizes in each direction
  363.  * total (sx,sy) is sum of all sub-boxes, max (mx,my) is max of sub-boxes
  364.  * also inherit filler count
  365.  */
  366.    my = mx = sx = sy = nf = 0;
  367.    for (b=box->sub; b; b=b->next) {
  368.       sx += b->xs;
  369.       sy += b->ys;
  370.       if (b->type == box->type || b->type == FILL) nf += b->nfil;
  371.       if (b->xs > mx) mx = b->xs;
  372.       if (b->ys > my) my = b->ys;
  373.    }
  374.    box->nfil = nf;
  375.  
  376. /* For horizontal boxes, bounding box is sum in x and max in y,
  377.  * for vertical, bouding box is max in x and sum in y
  378.  */
  379.    if (box->type == HBOX) {
  380.       box->xs = sx;
  381.       box->ys = my;
  382.    } else if (box->type == VBOX) {
  383.       box->xs = mx;
  384.       box->ys = sy;
  385.    } else printf ("Problem city --\nImpossible case\n");
  386. }
  387.  
  388.  
  389. short Layin();
  390.  
  391. /* Compute the layout of the boxes internal to this box
  392.  * Given that this box has correct location
  393.  * The box size computed by Format() is a minimum size,
  394.  * MX and MY are the max that the box can be expanded by filler
  395.  */
  396. Layout (box,mx,my)
  397.    BOX *box;
  398.    short mx,my;
  399. {
  400.    BOX *b;
  401.    short ish,z,nfil;
  402.    long gap,ifil;
  403.  
  404. /* handle basis cases
  405.  */
  406.    if (!box) {
  407.       printf ("Bad leaf nodes\n");
  408.       return;
  409.    }
  410. /* rules fill out to their max possible size
  411.  */
  412.    if (box->type == HRULE) {
  413.       box->xs = mx;
  414.    } else if (box->type == VRULE) {
  415.       box->ys = my;
  416.    }
  417.    if (box->type != HBOX && box->type != VBOX) return;
  418.  
  419. /* process only HBOX and VBOX cases recursively
  420.  * any onther case (a basis case) has its position set correctly
  421.  *  (see assumptions at head of function)
  422.  */
  423.    ish = (box->type == HBOX);
  424.    z = (ish ? box->x : box->y);
  425.    gap = (ish ? mx-box->xs : my-box->ys);
  426.  
  427. /* set positions setting filler sizes
  428.  */
  429.    ifil = 0;
  430.    Layin (box,&ifil,ish,z,box->nfil,gap);
  431. }
  432.  
  433.  
  434. /* Layout internal boxes
  435.  * Having this as a recursive function deals with
  436.  * the case of VBOXes within VBOXes
  437.  */
  438. short Layin (box,ifil,ish,z,nfil,gap)
  439.    BOX *box;
  440.    short *ifil,ish,z,nfil;
  441.    long gap;
  442. {
  443.    BOX *b;
  444.    short t;
  445.  
  446.    for (b=box->sub; b; b=b->next) {
  447.       if (ish) {
  448.          b->x = z;
  449.          b->y = box->y;
  450.       } else {
  451.          b->x = box->x;
  452.          b->y = z;
  453.       }
  454.       if (b->type == FILL) {
  455.          t = (gap*(*ifil+1))/nfil - (gap**ifil)/nfil;
  456.          (*ifil)++;
  457.          if (ish) b->xs = t; else b->ys = t;
  458.       } else if ((ish && b->type==HBOX) || (!ish && b->type==VBOX)) {
  459.          if (ish) b->ys = box->ys; else b->xs = box->xs;
  460.          t = Layin (b,ifil,ish,z,nfil,gap) - z;
  461.          if (ish) b->xs = t; else b->ys = t;
  462.       } else {
  463.          Layout (b,box->xs,box->ys);
  464.       }
  465.       z += (ish ? b->xs : b->ys);
  466.    }
  467.    return z;
  468. }
  469.  
  470.  
  471. /* Recursively prints this box and all its contents
  472.  */
  473. PrintBox (box,lev)
  474.    BOX *box;
  475.    short lev;
  476. {
  477.    int i;
  478.  
  479.    if (!box) return;
  480.  
  481.    for (i=0; i<lev; i++) printf ("  ");
  482.    printf ("%s (%d,%d) %dx%d", BoxType(box->type),
  483.     box->x,box->y, box->xs,box->ys);
  484.    if (box->type == TEXT) printf (" <%s>", box->val);
  485.    if (box->gid>0) printf (" [%d]", box->gid);
  486.    printf ("\n");
  487.    PrintBox (box->sub,lev+1);
  488.    PrintBox (box->next,lev);
  489. }
  490.  
  491.  
  492. /* Renders the text boxes in their correct locations in the window.
  493.  * Recursive.
  494.  */
  495. DisplayBox (win,box,biasx,biasy)
  496.    struct Window *win;
  497.    struct Box *box;
  498.    short biasx,biasy;
  499. {
  500.    if (!box) return;
  501.  
  502.    if (box->type == TEXT) {
  503.       it.IText = (UBYTE*)box->val;
  504.       it.LeftEdge = box->x;
  505.       it.TopEdge = box->y;
  506.       it.FrontPen = box->col;
  507.       PrintIText (win->RPort,&it,(LONG)biasx,(LONG)biasy);
  508.    }
  509.    DisplayBox (win,box->sub,biasx,biasy);
  510.    DisplayBox (win,box->next,biasx,biasy);
  511. }
  512.  
  513.  
  514.  
  515. /* INPUT SECTION */
  516.  
  517.  
  518. /* Returns true for "c" a blank
  519.  */
  520. BOOL Blank(c)
  521.    char c;
  522. {
  523.    return (c==' ' || c=='\n' || c=='\t');
  524. }
  525.  
  526.  
  527. /* Returns next non-blank char
  528.  */
  529. char NextChar()
  530. {
  531.    char c;
  532.    while (Blank(c=(char)(gc=getc(file))));
  533.    return c;
  534. }
  535.  
  536.  
  537. /* read a number if there is one
  538.  * otherwise return false and don't change n's value 
  539.  */
  540. BOOL Qnum(n,radix)
  541.    short *n,radix;
  542. {
  543.    char c;
  544.    short i=0;
  545.    BOOL isnum=FALSE;
  546.  
  547.    c = NextChar();
  548.    while (c >= '0' && c <= '9') {
  549.       isnum = TRUE;
  550.       i = i*radix + (c-'0');
  551.       c = (char)(gc=getc(file));
  552.    }
  553.    BACKSPACE;
  554.  
  555.    if (isnum) *n = i;
  556.    return isnum;
  557. }
  558.  
  559.  
  560. /* Reads a double-quoted string like
  561.  * "stuff"
  562.  * from the file into a place in the string buffer.  Returns
  563.  * pointer to the string constant.
  564.  */
  565. char *ReadString()
  566. {
  567.    short oldpos;
  568.    char c,*cp;
  569.  
  570.    oldpos = bufpos;
  571.    cp = &buf[bufpos];
  572.    c = NextChar();
  573.    if (c != '\"') {
  574.       printf ("String not found\n");
  575.       return 0;
  576.    }
  577.    while ((c=(char)(gc=getc(file))) != '\"') buf[bufpos++] = c;
  578.    buf[bufpos++] = '\0';
  579.    return cp;
  580. }
  581.  
  582.  
  583. /* Read ID of the form
  584.  * :number
  585.  * if there is one.  If not, return 0.
  586.  * Number is read as hex.
  587.  */
  588. short ReadID()
  589. {
  590.    short id;
  591.    char c;
  592.  
  593.    c = NextChar();
  594.    if (c == ':') {
  595.       fscanf (file, "%x", &id);
  596.       ngad++;
  597.       return id;
  598.    } else {
  599.       BACKSPACE;
  600.       return 0;
  601.    }
  602. }
  603.  
  604.  
  605. BOX *ReadBoxList ();
  606.  
  607. /* Get a box from the open file
  608.  */
  609. BOX *ReadBox ()
  610. {
  611.    char c;
  612.    BOX *b;
  613.  
  614.    c = NextChar();
  615.  
  616.    if (c == 'f') return NewBox (FILL);
  617.    if (c == '-') {
  618.       b = NewBox (HRULE);
  619.       b->ys = 1;
  620.       b->col = def_bcol;
  621.       return b;
  622.    }
  623.    if (c == '|') {
  624.       b = NewBox (VRULE);
  625.       b->xs = 1;
  626.       b->col = def_bcol;
  627.       return b;
  628.    }
  629.    if (c == '(') {
  630.       c = NextChar();
  631.       switch (c) {
  632.        case 'h':
  633.          b = NewBox (HBOX);
  634.          b->sub = ReadBoxList ();
  635.          break;
  636.        case 'v':
  637.          b = NewBox (VBOX);
  638.          b->sub = ReadBoxList ();
  639.          break;
  640.        case 't':
  641.          ntxt++;
  642.          b = NewBox (TEXT);
  643.          b->col = def_tcol;
  644.          Qnum (&b->col,10);
  645.          b->val = ReadString();
  646.          if (!b->val) {
  647.             FreeBox (b);
  648.             return 0;
  649.          }
  650.          b->xs = strlen(b->val)*8;
  651.          b->ys = 8;
  652.          break;
  653.        case 'b':
  654.          b = NewBox (BLOK);
  655.          fscanf (file, "%d%d", &b->xs, &b->ys);
  656.          break;
  657.        case '-':
  658.          b = NewBox (HRULE);
  659.          fscanf (file, "%d", &b->ys);
  660.          b->col = def_bcol;
  661.          Qnum (&b->col,10);
  662.          break;
  663.        case '|':
  664.          b = NewBox (VRULE);
  665.          fscanf (file, "%d", &b->xs);
  666.          b->col = def_bcol;
  667.          Qnum (&b->col,10);
  668.          break;
  669.        default:
  670.          printf ("Unknown Key Char\n");
  671.          return 0;
  672.       }
  673.  
  674.       c = NextChar();
  675.       if (c != ')') {
  676.          printf ("parse problem - expected ')'\n");
  677.          FreeBox (b);
  678.          return 0;
  679.       }
  680.       b->gid = ReadID();
  681.       return b;
  682.  
  683.    } else {
  684.       BACKSPACE;
  685.       return 0;
  686.    }
  687. }
  688.  
  689.  
  690. /* Read a list of boxes from the file stream
  691.  * Recursive - read a box, then read a list.
  692.  */
  693. BOX *ReadBoxList ()
  694. {
  695.    BOX *b;
  696.  
  697.    b = ReadBox ();
  698.    if (!b) return 0;
  699.  
  700.    b->next = ReadBoxList();
  701.    return b;
  702. }
  703.  
  704.  
  705. /* Reads the list of gadget info from the end of the file
  706.  * Reads as much as there is
  707.  * format is:
  708.  *   number {s|p} {:string} string
  709.  * stuff in {}'s is optional
  710.  */
  711. ReadGadInfo()
  712. {
  713.    char c;
  714.    short i;
  715.  
  716.    i = 0;
  717.    while (Qnum(&i,16)) {
  718.       ginfo[lgad].gid = i;
  719.       ginfo[lgad].gnam = NULL;
  720.       ginfo[lgad].str = -1;
  721.       ginfo[lgad].prp = -1;
  722.       c = NextChar();
  723.       if (c == 's') {
  724.          ginfo[lgad].str = nstr++;
  725.          c = NextChar();
  726.       } else if (c == 'p') {
  727.          ginfo[lgad].prp = nprp++;
  728.          c = NextChar();
  729.       }
  730.       if (c==':') {
  731.          ginfo[lgad].gnam = ReadString();
  732.       } else {
  733.          BACKSPACE;
  734.       }
  735.       ginfo[lgad++].actf = ReadString();
  736.    }
  737.  
  738. /* print out list of gadget info structs for pure delight
  739.  */
  740.    for (i=0; i<lgad; i++) {
  741.       printf ("gad %d %d, <%s>", i, ginfo[i].gid, ginfo[i].actf);
  742.       if (ginfo[i].gnam) printf (" [%s]", ginfo[i].gnam);
  743.       if (ginfo[i].str != -1) printf (" (string)");
  744.       if (ginfo[i].prp != -1) printf (" (prop)");
  745.       printf ("\n");
  746.    }
  747. }
  748.  
  749.  
  750. /* To read file:
  751.  *  open, read base name, read optional default border and text colors
  752.  *  read a box (a BIG box), read gadget info blocks, close
  753.  */
  754. BOX *ReadFile (nam)
  755.    char *nam;
  756. {
  757.    BOX *box;
  758.    short i;
  759.  
  760.    printf ("opening file <%s>\n", nam);
  761.    file = fopen (nam,"r");
  762.    if (!file) {
  763.       printf ("Cannot open %s\n", nam);
  764.       exit(0);
  765.    }
  766.    fscanf (file, "%s", base);
  767.    Qnum (&def_bcol,10);
  768.    Qnum (&def_tcol,10);
  769.    box = ReadBox ();
  770.    ReadGadInfo();
  771.  
  772.    fclose (file);
  773.    return box;
  774. }
  775.  
  776.  
  777. /* OUTPUT SECTION (this whole thing is crufty, sorry)
  778.  * (except perhaps the Border stuff)
  779.  */
  780.  
  781.  
  782. /* Recursively locate and print the string for a given gadget id
  783.  * Truncate trailing spaces
  784.  */
  785. WriteBufEntry (id,box)
  786.    short id;
  787.    BOX *box;
  788. {
  789.    int i;
  790.  
  791.    if (!box) return;
  792.  
  793.    if (box->gid == id) {
  794.       for (i=strlen(box->val)-1; i>0; i--) {
  795.          if (box->val[i] == ' ') box->val[i] = '\0';
  796.           else break;
  797.       }
  798.       fprintf (file, "\"%s\"", box->val);
  799.       if (++istr != nstr) fprintf (file, ", ");
  800.       box->val = NULL;
  801.       ntxt--;
  802.    } else {
  803.       WriteBufEntry (id,box->sub);
  804.       WriteBufEntry (id,box->next);
  805.    }
  806. }
  807.  
  808.  
  809. /* Output the StringInfo structs for all the string gadgets
  810.  */
  811. WriteStrInfo ()
  812. {
  813.    int i;
  814.  
  815.    for (i=0; i<lgad; i++) {
  816.       if (ginfo[i].str != -1) {
  817.          fprintf (file, "  {&%s_nbuf[%d][0],undo,0,NUMCHR,0}",base,istr++);
  818.          if (istr == nstr) fprintf (file, "\n");
  819.           else fprintf (file, ",\n");
  820.       }
  821.    }
  822. }
  823.  
  824.  
  825. /* Output the PropInfo structs for all the proportional gadgets
  826.  */
  827. WritePrpInfo ()
  828. {
  829.    int i;
  830.  
  831.    for (i=0; i<lgad; i++) {
  832.       if (ginfo[i].prp != -1) {
  833.          fprintf (file, "  {AUTOKNOB|FREEHORIZ|PROPBORDERLESS,\
  834. 0x8000,0,0x8000,0x8000}");
  835.          if (++iprp == nprp) fprintf (file, "\n");
  836.           else fprintf (file, ",\n");
  837.       }
  838.    }
  839. }
  840.  
  841.  
  842. /* Recursively locate and output Gadget structs for all gadgets
  843.  */
  844. WriteGad (box)
  845.    BOX *box;
  846. {
  847.    int i,j,l,t;
  848.  
  849.    if (!box) return;
  850.  
  851.    if (box->gid) {
  852. /* find the Gadinfo entry for this gadget.  search backwards so that a
  853.  * failure to locate lands us on Gadinfo 0, the default
  854.  */
  855.       for (i=lgad-1; i>=0; i--)
  856.        if (ginfo[i].gid == box->gid || i == 0) break;
  857.  
  858.       if (++igad==ngad) {
  859.          fprintf (file, "  {NULL");
  860.       } else {
  861.          fprintf (file, "  {&%s_gad[%d]", base,igad);
  862.       }
  863.       fprintf (file, ",%d,%d,%d,%d,\n   ", box->x,box->y,box->xs,box->ys);
  864.       if (index(ginfo[i].actf, 'B')) fprintf (file, "GADGHBOX,");
  865.        else fprintf (file, "GADGHCOMP,");
  866.  
  867.       t = 0;
  868.       if (l = strlen(ginfo[i].actf)) for (j=0; j<l; j++) {
  869.          switch (ginfo[i].actf[j]) {
  870.           case 't':
  871.           case 'v':
  872.           case 'e':
  873.           case 'i':
  874.           case 'c':
  875.           case 'f':
  876.             if (t) fprintf (file, "|");
  877.             t = 1;
  878.          }
  879.          switch (ginfo[i].actf[j]) {
  880.           case 't': fprintf (file, "TOGGLESELECT"); break;
  881.           case 'v': fprintf (file, "RELVERIFY"); break;
  882.           case 'e': fprintf (file, "ENDGADGET"); break;
  883.           case 'i': fprintf (file, "GADGIMMEDIATE"); break;
  884.           case 'c': fprintf (file, "STRINGCENTER"); break;
  885.           case 'f': fprintf (file, "FOLLOWMOUSE"); break;
  886.          }
  887.       } else fprintf (file, "0");
  888.  
  889.       if (ginfo[i].str != -1) fprintf (file, ",STRGADGET");
  890.        else if (ginfo[i].prp != -1) fprintf (file, ",PROPGADGET");
  891.        else fprintf (file, ",BOOLGADGET");
  892.       fprintf (file, "|REQGADGET,\n   ");
  893.       if (ginfo[i].prp != -1)
  894.         fprintf (file, "(APTR)&%s_pimg[%d],", base,ginfo[i].prp);
  895.        else fprintf (file, "NULL,");
  896.       fprintf (file, "NULL,NULL,0,");
  897.       if (ginfo[i].str != -1)
  898.         fprintf (file, "(APTR)&%s_sinfo[%d],", base,ginfo[i].str);
  899.        else if (ginfo[i].prp != -1)
  900.         fprintf (file, "(APTR)&%s_pinfo[%d],", base,ginfo[i].prp);
  901.        else fprintf (file, "NULL,");
  902.  
  903.       if (ginfo[i].gnam) fprintf (file, "%s,NULL}", ginfo[i].gnam);
  904.        else fprintf (file, "0x%x,NULL}", box->gid);
  905.       if (igad==ngad) fprintf (file, "\n");
  906.        else fprintf (file, ",\n");
  907.    }
  908.    WriteGad (box->sub);
  909.    WriteGad (box->next);
  910. }
  911.  
  912.  
  913. /* Recursively locate and output IntuiText structs for all TEXT boxes
  914.  */
  915. WriteText (box)
  916.    BOX *box;
  917. {
  918.    if (!box) return;
  919.  
  920.    if (box->type == TEXT && box->val) {
  921.       fprintf (file, "  {%d,0,JAM2,%d,%d,&ta,(UBYTE*)\"%s\",",
  922.        box->col,box->x,box->y,box->val);
  923.       if (++itxt==ntxt) {
  924.          fprintf (file, "NULL}\n");
  925.       } else {
  926.          fprintf (file, "&%s_txt[%d]},\n", base,itxt);
  927.       }
  928.    }
  929.    WriteText (box->sub);
  930.    WriteText (box->next);
  931. }
  932.  
  933.  
  934. /* Write out list of Border structs from main list
  935.  */
  936. WriteBorder ()
  937. {
  938.    register struct Border *b;
  939.    register short i=0,j=0;
  940.  
  941.    fprintf (file, "struct Border %s_brd[] = {\n", base);
  942.    for (b=blst; b; b=b->NextBorder) {
  943.       fprintf (file, "  {0,0,%d,0,JAM1,%d,&%s_brd_XY[%d],",
  944.        b->FrontPen,b->Count,base,i);
  945.       i += b->Count*2;
  946.       if (b->NextBorder) {
  947.          fprintf (file, "&%s_brd[%d]},\n", base,++j);
  948.       } else {
  949.          fprintf (file, "NULL}\n");
  950.       }
  951.    }
  952.    fprintf (file, "};\n");
  953. }
  954.  
  955.  
  956. /* Write out list of XY arrays from Border struct main list
  957.  */
  958. WriteBorderXY ()
  959. {
  960.    register struct Border *b;
  961.    register short i;
  962.  
  963.    fprintf (file, "short %s_brd_XY[] = {\n", base);
  964.    for (b=blst; b; b=b->NextBorder) {
  965.       fprintf (file, "  ");
  966.       for (i=0; i<b->Count; i++) {
  967.          fprintf (file, "%d,%d", b->XY[i*2],b->XY[i*2+1]);
  968.          if (i!=b->Count-1 || b->NextBorder) fprintf (file, ", ");
  969.       }
  970.       fprintf (file, "\n");
  971.    }
  972.    fprintf (file, "};\n");
  973. }
  974.  
  975.  
  976. /* The main output function
  977.  */
  978. WriteFile (name,box)
  979.    char *name;
  980.    BOX *box;
  981. {
  982.    short i;
  983.  
  984.    if (!(file = fopen (name, "w"))) {
  985.       printf ("Can't open output file\n");
  986.       return;
  987.    }
  988.  
  989. /* write optional string gadget structs
  990.  */
  991.    if (nstr) {
  992.       fprintf (file,"UBYTE %s_nbuf[%d][NUMCHR] = {\n ", base,nstr);
  993.       for (i=0; i<lgad; i++)
  994.        if (ginfo[i].str != -1) WriteBufEntry (ginfo[i].gid,box);
  995.       istr = 0;
  996.       fprintf (file,"\n};\n\nstruct StringInfo %s_sinfo[] = {\n", base);
  997.       WriteStrInfo();
  998.       fprintf (file,"\n};\n");
  999.    }
  1000.  
  1001. /* write optional prop gadget structs
  1002.  */
  1003.    if (nprp) {
  1004.       fprintf (file,"\nstruct Image %s_pimg[%d];\n", base,nprp);
  1005.       fprintf (file,"struct PropInfo %s_pinfo[] = {\n", base);
  1006.       WritePrpInfo();
  1007.       fprintf (file,"};\n");
  1008.    }
  1009.  
  1010. /* write gadgets, text and borders (not optional)
  1011.  */
  1012.    fprintf (file,"\nstruct Gadget %s_gad[] = {\n", base);
  1013.    WriteGad (box);
  1014.    fprintf (file,"};\n\nstruct IntuiText %s_txt[] = {\n", base);
  1015.    WriteText (box);
  1016.    fprintf (file, "};\n\n");
  1017.    WriteBorderXY ();
  1018.    WriteBorder ();
  1019.  
  1020. /* the requester itself
  1021.  */
  1022.    fprintf (file, "\n\nstruct Requester %s_req = {\n\
  1023.   NULL,0,0,%d,%d,0,0,%s_gad,%s_brd,%s_txt,0,0,\n\
  1024.   NULL,{NULL},NULL,NULL,{NULL}};\n", base,box->xs,box->ys,base,base,base);
  1025.  
  1026.    fclose (file);
  1027. }
  1028.  
  1029.  
  1030. main(argc,argv)
  1031.    int argc;
  1032.    char *argv[];
  1033. {
  1034.    if (argc < 2 || argc > 4) {
  1035.       printf ("Usage: blk <file> [<outfile> | %%]\n");
  1036.       exit(0);
  1037.    }
  1038.  
  1039.    IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L);
  1040.    if (IntuitionBase) {
  1041.       Body (argc,argv);
  1042.       CloseLibrary (IntuitionBase);
  1043.    }
  1044. }
  1045.  
  1046.  
  1047. Body(argc,argv)
  1048.    int argc;
  1049.    char *argv[];
  1050. {
  1051.    struct Window *win;
  1052.    BOX *b;
  1053.    short h,w;
  1054.  
  1055.    b = ReadFile (argv[1]);
  1056.    Format (b);
  1057.    b->x = b->y = 0;
  1058.    Layout (b,b->xs,b->ys);
  1059.    if (argc == 3 && argv[2][0] == '%') PrintBox (b,0);
  1060.    CreateBorder (b);
  1061.    MergeBorders ();
  1062.    MergeLinear ();
  1063.  
  1064. /* open a window to preview the requester layout
  1065.  */
  1066.    w = b->xs+20;
  1067.    h = b->ys+20;
  1068.    if (w>640 || h>200) printf ("requester too large\n");
  1069.     else {
  1070.       nwin.Width = w;
  1071.       nwin.Height = h;
  1072.       win = OpenWindow (&nwin);
  1073.       if (win) {
  1074.          DrawBorder (win->RPort,blst,(LONG)win->BorderLeft+5,(LONG)win->BorderTop+5);
  1075.          DisplayBox (win,b,win->BorderLeft+5,win->BorderTop+5);
  1076. /* if output specified, write it out, otherwise wait */
  1077.          if (argc == 3 && argv[2][0] != '%') WriteFile(argv[2],b);
  1078.           else Delay (300L);
  1079.          CloseWindow (win);
  1080.       } else printf ("Unable to open Window\n");
  1081.    }
  1082.  
  1083.    FreeBorder ();
  1084.    FreeBox (b);
  1085. }
  1086.